package com.agriculture.service;

import com.agriculture.dto.DevicePathDto;
import com.agriculture.dto.PositionDto;
import com.agriculture.entity.DevicePositionHistory;
import com.agriculture.entity.GeoDevicePath;
import com.agriculture.repository.DevicePositionHistoryRepository;
import com.agriculture.repository.GeoDevicePathRepository;
import com.agriculture.repository.GeoDeviceRepository;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class GeoDevicePathService {
    
    @Autowired
    private GeoDevicePathRepository pathRepository;
    
    @Autowired
    private GeoDeviceRepository deviceRepository;
    
    @Autowired
    private DevicePositionHistoryRepository positionHistoryRepository;
    
    private final GeometryFactory geometryFactory = new GeometryFactory();
    
    public List<GeoDevicePath> getAllPaths() {
        return pathRepository.findAll();
    }
    
    public Optional<GeoDevicePath> getPathById(Integer id) {
        return pathRepository.findById(id);
    }
    
    public List<GeoDevicePath> getPathsByDeviceId(Integer deviceId) {
        return pathRepository.findByDeviceId(deviceId);
    }
    
    public List<GeoDevicePath> getPathsByDeviceAndTimeRange(Integer deviceId, LocalDateTime startTime, LocalDateTime endTime) {
        // 首先尝试从预定义路径中查找
        List<GeoDevicePath> predefinedPaths = pathRepository.findByDeviceIdAndTimeRange(deviceId, startTime, endTime);
        
        // 如果没有预定义路径，从历史位置数据生成路径
        if (predefinedPaths.isEmpty()) {
            return generatePathsFromHistoryData(deviceId, startTime, endTime);
        }
        
        return predefinedPaths;
    }
    
    /**
     * 从历史位置数据生成轨迹路径
     */
    public List<GeoDevicePath> generatePathsFromHistoryData(Integer deviceId, LocalDateTime startTime, LocalDateTime endTime) {
        List<DevicePositionHistory> historyPositions = positionHistoryRepository
            .findByDeviceIdAndTimeRange(deviceId, startTime, endTime);
        
        List<GeoDevicePath> generatedPaths = new ArrayList<>();
        
        if (!historyPositions.isEmpty()) {
            // 创建一个路径对象包含所有历史位置点
            GeoDevicePath path = new GeoDevicePath();
            path.setDeviceId(deviceId);
            path.setPathName("历史轨迹 " + startTime.toLocalDate() + " 至 " + endTime.toLocalDate());
            path.setStartTime(historyPositions.get(0).getRecordedTime());
            path.setEndTime(historyPositions.get(historyPositions.size() - 1).getRecordedTime());
            
            // 将历史位置点转换为LineString
            Coordinate[] coordinates = historyPositions.stream()
                .map(h -> new Coordinate(h.getPosition().getX(), h.getPosition().getY()))
                .toArray(Coordinate[]::new);
            
            if (coordinates.length >= 2) {
                LineString lineString = geometryFactory.createLineString(coordinates);
                path.setPathLine(lineString);
                path.setTotalDistance(calculatePathDistance(coordinates));
                
                generatedPaths.add(path);
            }
        }
        
        return generatedPaths;
    }
    
    public GeoDevicePath savePath(GeoDevicePath path) {
        return pathRepository.save(path);
    }
    
    public DevicePathDto convertToDto(GeoDevicePath path) {
        DevicePathDto dto = new DevicePathDto();
        dto.setId(path.getId());
        dto.setDeviceId(path.getDeviceId());
        dto.setPathName(path.getPathName());
        dto.setStartTime(path.getStartTime());
        dto.setEndTime(path.getEndTime());
        dto.setTotalDistance(path.getTotalDistance());
        
        // 获取设备名称
        deviceRepository.findById(path.getDeviceId()).ifPresent(device -> {
            dto.setDeviceName(device.getDeviceName());
        });
        
        // 转换路径点
        List<PositionDto> points = new ArrayList<>();
        if (path.getPathLine() != null) {
            Coordinate[] coordinates = path.getPathLine().getCoordinates();
            for (Coordinate coord : coordinates) {
                points.add(new PositionDto(coord.x, coord.y));
            }
        }
        dto.setPathPoints(points);
        
        return dto;
    }
    
    /**
     * 专门用于获取历史轨迹的方法
     */
    public List<DevicePathDto> getHistoryPathsByDeviceAndTimeRange(Integer deviceId, LocalDateTime startTime, LocalDateTime endTime) {
        // 直接从历史位置数据生成轨迹
        List<GeoDevicePath> historyPaths = generatePathsFromHistoryData(deviceId, startTime, endTime);
        
        return historyPaths.stream()
                .map(this::convertToDto)
                .collect(ArrayList::new, (list, item) -> list.add(item), (list1, list2) -> list1.addAll(list2));
    }
    
    /**
     * 获取原始历史位置数据 - 用于调试
     */
    public List<DevicePositionHistory> getHistoryPositions(Integer deviceId, LocalDateTime startTime, LocalDateTime endTime) {
        if (startTime != null && endTime != null) {
            return positionHistoryRepository.findByDeviceIdAndTimeRange(deviceId, startTime, endTime);
        } else {
            return positionHistoryRepository.findByDeviceIdOrderByRecordedTimeAsc(deviceId);
        }
    }
    
    public GeoDevicePath createPathFromPoints(Integer deviceId, List<PositionDto> points, String pathName, 
                                             LocalDateTime startTime, LocalDateTime endTime) {
        GeoDevicePath path = new GeoDevicePath();
        path.setDeviceId(deviceId);
        path.setPathName(pathName);
        path.setStartTime(startTime);
        path.setEndTime(endTime);
        
        // 创建LineString
        Coordinate[] coordinates = points.stream()
            .map(p -> new Coordinate(p.getLongitude(), p.getLatitude()))
            .toArray(Coordinate[]::new);
        LineString lineString = geometryFactory.createLineString(coordinates);
        path.setPathLine(lineString);
        
        // 计算总距离（简化计算）
        path.setTotalDistance(calculatePathDistance(coordinates));
        
        return pathRepository.save(path);
    }
    
    private Double calculatePathDistance(Coordinate[] coordinates) {
        double totalDistance = 0.0;
        for (int i = 1; i < coordinates.length; i++) {
            totalDistance += calculateHaversineDistance(
                coordinates[i-1].y, coordinates[i-1].x,
                coordinates[i].y, coordinates[i].x
            );
        }
        return totalDistance;
    }
    
    private double calculateHaversineDistance(double lat1, double lon1, double lat2, double lon2) {
        final int R = 6371000; // 地球半径(米)
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                   Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
                   Math.sin(dLon/2) * Math.sin(dLon/2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        return R * c;
    }
}